package net.kingborn.test;

import java.io.File;
import java.io.IOException;
import java.nio.charset.CodingErrorAction;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import net.kingborn.common.util.JsonKit;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.cookie.ClientCookie;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.util.EntityUtils;

import com.alibaba.fastjson.JSONObject;

/**
 * HTTP请求工具
 * 
 * @author Chen Wei
 *
 */
@SuppressWarnings("deprecation")
public class HttpUtils {
	
    private static PoolingHttpClientConnectionManager connManager = null;
    private static CloseableHttpClient httpClient = null;
    
    /** 
     * 连接超时时间
     */  
    public static final int CONNECT_TIMEOUT = 180000;
    
    /**
     * 套接字超时时间
     */
    public static final int SOCKET_TIMEOUT = 180000;
    
    /**
     * 连接池中 连接请求执行被阻塞的超时时间
     */
    public static final long REQUEST_TIMEOUT = 180000;
     
    static {
        try {
            SSLContext sslContext = SSLContexts.custom().useTLS().build();
            sslContext.init(null,
                    new TrustManager[] { new X509TrustManager() {
                         
                        public X509Certificate[] getAcceptedIssuers() {
                            return null;
                        }
 
                        public void checkClientTrusted(
                                X509Certificate[] certs, String authType) {
                        }
 
                        public void checkServerTrusted(
                                X509Certificate[] certs, String authType) {
                        }
                    }}, null);
            
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", new SSLConnectionSocketFactory(sslContext))
                    .build();
             
            connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            httpClient = HttpClients.custom().setConnectionManager(connManager).build();
            // Create socket configuration
            SocketConfig socketConfig = SocketConfig.custom().setTcpNoDelay(true).build();
            connManager.setDefaultSocketConfig(socketConfig);
            // Create message constraints
            /*MessageConstraints messageConstraints = MessageConstraints.custom()
                .setMaxHeaderCount(200)
                .setMaxLineLength(2000)
                .build();*/
            // Create connection configuration
            ConnectionConfig connectionConfig = ConnectionConfig.custom()
                .setMalformedInputAction(CodingErrorAction.IGNORE)
                .setUnmappableInputAction(CodingErrorAction.IGNORE)
                .setCharset(Consts.UTF_8)
                // .setMessageConstraints(messageConstraints)
                .build();
            connManager.setDefaultConnectionConfig(connectionConfig);
            connManager.setMaxTotal(200);
            connManager.setDefaultMaxPerRoute(20);
            
        } catch (KeyManagementException e) {
            e.printStackTrace();
            
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
	
	/**
	 * 执行post请求
	 * 
	 * @param url
	 * @return
	 */
	public static String doHttpPost(String url) {
		HttpPost httpPost;
		
		httpPost = new HttpPost(url);
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(SOCKET_TIMEOUT)
                .setConnectTimeout(CONNECT_TIMEOUT)
                // .setConnectionRequestTimeout(timeout)
                .setExpectContinueEnabled(false).build();
        httpPost.setConfig(requestConfig);
	
		String result = null;
		CloseableHttpResponse response = null;
		
		try {
			response = httpClient.execute(httpPost);
			
			result = EntityUtils.toString(response.getEntity());
			
		} catch (ClientProtocolException e) {
			e.printStackTrace();
			
		} catch (IOException e) {
			e.printStackTrace();
			
		} finally {
			if (response != null) {
				try {
					response.close();
					
				} catch (IOException e) {
					e.printStackTrace();
					
				}
			}
			httpPost.releaseConnection();
		}
		
		return result;
	}

	/**
	 * 执行Post请求
	 * 
	 * @param url
	 * @return
	 */
	public static String doHttpPost(BaseUrl baseUrl) {
		return doHttpPost(baseUrl, null);
	}
	
	/**
	 * 执行Post请求，如果有cookie则带上
	 * 
	 * @param url
	 * @return
	 */
	public static String doHttpPost(BaseUrl baseUrl, Map<String, Object> cookieMap) {
		return doHttpPost(baseUrl, null, null, cookieMap);
	}

	/**
	 * 执行httpPost
	 * 
	 * @param baseUrl
	 * @param postParamsMap
	 * @param cookieMap
	 * @return
	 */
	public static String doHttpPost(BaseUrl baseUrl, Map<String, Object> getParamsMap, 
			Map<String, Object> postParamsMap, Map<String, Object> cookieMap) {
		return doHttpPost(baseUrl, getParamsMap, postParamsMap, cookieMap, null);
	}
	
	/**
	 * 执行httpPost
	 * 
	 * @param baseUrl
	 * @param postParamsMap
	 * @param cookieMap
	 * @return
	 */
	public static String doHttpPost(BaseUrl baseUrl, Map<String, Object> getParamsMap, 
			Map<String, Object> postParamsMap, Map<String, Object> cookieMap, Map<String, String> filePathMap) {
		return doHttpPost(baseUrl, getParamsMap, null, postParamsMap, cookieMap, filePathMap);
	}
	
	public static String doHttpPost(BaseUrl baseUrl, Map<String, Object> postParamsMap, Map<String, String> headerMap) {
		return doHttpPost(baseUrl, null, headerMap, postParamsMap, null, null);
	}
	
	/**
	 * 执行http post操作
	 * 
	 * @param baseUrl
	 * @param getParamsMap
	 * @param headerMap
	 * @param postParamsMap
	 * @param cookieMap
	 * @param filePathMap
	 * @return
	 */
	public static String doHttpPost(BaseUrl baseUrl, Map<String, Object> getParamsMap, Map<String, String> headerMap, 
			Map<String, Object> postParamsMap, Map<String, Object> cookieMap, Map<String, String> filePathMap) {
		HttpPost httpPost = new HttpPost(createWholeUrl(baseUrl.toString(), getParamsMap));
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(SOCKET_TIMEOUT)
                .setConnectTimeout(CONNECT_TIMEOUT)
                // .setConnectionRequestTimeout(timeout)
                .setExpectContinueEnabled(false).build();
        httpPost.setConfig(requestConfig);

		System.out.println(createWholeUrl(baseUrl.toString(), getParamsMap));
		
		if (headerMap != null && headerMap.size() > 0) {
			Set<String> headerKeySet = headerMap.keySet();
			for (String headerKey : headerKeySet) {
				httpPost.setHeader(headerKey, headerMap.get(headerKey));
			}
		}
		
		if (filePathMap != null && filePathMap.size() > 0) {
			MultipartEntityBuilder builder = MultipartEntityBuilder.create();
			
			Set<String> filePathKeySet = filePathMap.keySet();
			for (String filePathKey : filePathKeySet) {
				File file = new File(filePathMap.get(filePathKey));
				builder.addBinaryBody(filePathKey, file);
			}
			
			if (postParamsMap != null && postParamsMap.keySet().size() > 0) {
				Set<String> postParamKeySet = postParamsMap.keySet();
				for (String postParamKey : postParamKeySet) {
					builder.addTextBody(postParamKey, postParamsMap.get(postParamKey).toString(), ContentType.create("application/x-www-form-urlencoded", "UTF-8"));
				}
			}
			
			HttpEntity httpEntity = builder.build();
			httpPost.setEntity(httpEntity);
			
		} else {
			// StringEntity stringEntity = new StringEntity(createParamsStr(postParamsMap), "UTF-8");
			// stringEntity.setContentType("application/x-www-form-urlencoded");
			
			StringEntity stringEntity = new StringEntity(JsonKit.toJson(postParamsMap), "UTF-8");
			stringEntity.setContentType("application/json");
			
			httpPost.setEntity(stringEntity);
		}
		
		String result = null;
		CloseableHttpResponse response = null;
		
		try {
			CookieStore cookieStore = new BasicCookieStore();
			if (cookieMap != null && cookieMap.size() > 0) {
				Set<String> keySet = cookieMap.keySet();
				for (String key : keySet) {
					String value = cookieMap.get(key).toString();
					BasicClientCookie cookie = new BasicClientCookie(key, value);
					cookie.setVersion(0);
					cookie.setDomain(baseUrl.getDomain());
					cookie.setAttribute(ClientCookie.PORT_ATTR, baseUrl.getPort() + "");
					
					cookie.setPath(baseUrl.getPath());
					cookieStore.addCookie(cookie);
				}
				
			}
			httpClient = HttpClients
					.custom()
					.setConnectionManager(connManager)
					.setDefaultCookieStore(cookieStore).build();
			
			response = httpClient.execute(httpPost);
			System.out.println(response.getStatusLine());
			Header[] headers = response.getAllHeaders();
			for (Header header : headers) {
				System.out.println(header.getName() + ": " + header.getValue());
			}
			System.out.println("Content-Type: " + response.getHeaders("Content-Type"));

			result = EntityUtils.toString(response.getEntity(), "UTF-8");
			
			System.out.println("===================cookie start=======================");
			List<Cookie> cookies = cookieStore.getCookies();
			for (int index = 0; index < cookies.size(); index ++) {
				System.out.println("cookies: " + cookies.get(index));
			}
			System.out.println("===================cookie end=========================");
			
			
		} catch (ClientProtocolException e) {
			e.printStackTrace();
			
		} catch (IOException e) {
			e.printStackTrace();
			
		} finally {
			if (response != null) {
				try {
					response.close();
					
				} catch (IOException e) {
					e.printStackTrace();
					
				}
			}
			
			httpPost.releaseConnection();
		}
		
		return result;
	}
	
	/**
	 * 执行HttpGet
	 * 
	 * @param baseUrl
	 * @param getParamsMap
	 * @param headerMap
	 * @param cookieMap
	 * @return
	 */
	public static String doHttpGet(BaseUrl baseUrl, Map<String , Object> getParamsMap, Map<String, String> headerMap, Map<String, Object> cookieMap) {
		HttpGet httpGet = new HttpGet(createWholeUrl(baseUrl.toString(), getParamsMap));
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(SOCKET_TIMEOUT)
                .setConnectTimeout(CONNECT_TIMEOUT)
                // .setConnectionRequestTimeout(timeout)
                .setExpectContinueEnabled(false).build();
        httpGet.setConfig(requestConfig);
        
        System.out.println(createWholeUrl(baseUrl.toString(), getParamsMap));
		
		if (headerMap != null && headerMap.size() > 0) {
			Set<String> headerKeySet = headerMap.keySet();
			for (String headerKey : headerKeySet) {
				httpGet.setHeader(headerKey, headerMap.get(headerKey));
			}
		}
		String result = null;
		CloseableHttpResponse response = null;
		
		try {
			if (cookieMap != null && cookieMap.size() > 0) {
				CookieStore cookieStore = new BasicCookieStore();
				Set<String> keySet = cookieMap.keySet();
				for (String key : keySet) {
					String value = cookieMap.get(key).toString();
					BasicClientCookie cookie = new BasicClientCookie(key, value);
					cookie.setVersion(0);
					cookie.setDomain(baseUrl.getDomain());
					cookie.setAttribute(ClientCookie.PORT_ATTR, baseUrl.getPort() + "");
					
					cookie.setPath(baseUrl.getPath());
					cookieStore.addCookie(cookie);
				}
				
				httpClient = HttpClients
						.custom()
						.setConnectionManager(connManager)
						.setDefaultCookieStore(cookieStore).build();
				
			}
			
			response = httpClient.execute(httpGet);
			System.out.println(response.getStatusLine());
			
			result = EntityUtils.toString(response.getEntity());
			
		} catch (ClientProtocolException e) {
			e.printStackTrace();
			
		} catch (IOException e) {
			e.printStackTrace();
			
		} finally {
			if (response != null) {
				try {
					response.close();
					
				} catch (IOException e) {
					e.printStackTrace();
					
				}
			}
			
			httpGet.releaseConnection();
		}
		
		return result;
	}
	
	
	/**
	 * 创建完整的url 
	 * 
	 * @param baseUrl
	 * @param getParamsMap
	 * @return
	 */
	public static String createWholeUrl(String baseUrl, Map<String, Object> getParamsMap) {
		if (getParamsMap == null) {
			return baseUrl;
		}
		
		String getParams = createParamsStr(getParamsMap);
		if (getParams == null || "".equals(getParams)) {
			getParams = "";
			
		} else {
			getParams = "?" + getParams;
		}
		
		return baseUrl + getParams;
	}
	
	/**
	 * 组合请求字符串
	 * 
	 * @param getParamsMap
	 * @return
	 */
	public static String createParamsStr(Map<String, Object> getParamsMap) {
		if (getParamsMap == null) {
			return "";
		}
		
		Set<String> keySet = getParamsMap.keySet();
		if (keySet.size() == 0) {
			return "";
		}
		
		String paramsStr = "";
		for (String key : keySet) {
			paramsStr += key + "=" + getParamsMap.get(key) + "&";
		}
		paramsStr = paramsStr.substring(0, paramsStr.length() - 1);
		
		return paramsStr;
	}
	
}
